from flask import Blueprint, current_app, request, send_file, Response
import json, time, zlib, gzip
import numpy as np
import datetime
import utilsapp
from utilsapp import utils
from utilsapp.common import assign_value,  get_collection_name
from utilsapp.mysql_con import db_delete, db_insert, db_list
from utilsapp.mathself import (
    get_speed,
    GetEnvelope,
    get_rep,
    get_csd,
    GetFFT,
    get_erenges,
    get_histogram,
    bef_get_wave,
    get_sudu,
    GetFilter,
)
from utilsapp.utils import date_to_str

# import msgpack

bluePrint = Blueprint("diag", __name__)


@bluePrint.route("/wave/time", methods=["post"])
def get_wave_time():
    proj_no = request.json["proj_no"]
    stime = request.json["stime"]
    etime = request.json["etime"]
    saddr = request.json["saddr"]
    sport = request.json["sport"]
    channel = request.json["channel"]
    axial = request.json["axial"]
    wave_type = request.json["wave_type"]
    multi = assign_value(request.json, "multi")
    eigkey = request.json["eigkey"]

    mgdb = current_app.mgdb[f"ieplat_{proj_no}"]
    collection = mgdb[f"wave"]
    # 构造查询条件和投影参数
    query = {
        "$and": [
            {"_id": {"$gte": f"{sport}_{saddr}_{channel}_{axial}_{stime}"}},
            {"_id": {"$lte": f"{sport}_{saddr}_{channel}_{axial}_{etime}"}},
        ]
    }
    projection = {f"data.{wave_type}": 1, "_id": 1}
    # 执行查询
    result = collection.find(query, projection)
    try:
        if multi != "":
            d = [
                {
                    "id": t["_id"],
                    "value": t["data"][wave_type][eigkey],
                    **{
                        k: v
                        for k, v in t["data"][wave_type].items()
                        if k != f"{wave_type}_wave"
                    },
                }
                for t in result
            ]
        else:
            d = [
                {
                    "id": t["_id"],
                    "value": t["data"][wave_type][eigkey],
                }
                for t in result
            ]
        for item in d:
            sql = f"select * from note where name = '{item['id']}'"
            res = db_list(sql)
            item["note"] = res["data"]
    except Exception as e:
        return utils.ok(data=[])
    return utils.ok(d)


@bluePrint.route("/addNote", methods=["post"])
def addNote():
    a = request.json
    return db_insert("note", request.json)


@bluePrint.route("/deleteNote", methods=["post"])
def deleteNote():
    content = request.json["content"]
    name = request.json["name"]
    return db_delete(
        "note", f"WHERE content=%s and name=%s", {"content": content, "name": name}
    )


@bluePrint.route("/wave", methods=["post"])
def get_wave():
    proj_no = request.json["proj_no"]
    waveid = request.json["waveid"]
    wave_type = assign_value(request.json, "wave_type", "acc")
    flag = assign_value(request.json, "flag", ["wave"])
    waveFilter = assign_value(request.json, "waveFilter")
    low = assign_value(request.json, "low", 0)
    high = assign_value(request.json, "high", 0)
    mgdb = current_app.mgdb[f"ieplat_{proj_no}"]
    collection = mgdb[f"wave"]
    # 构造查询条件和投影参数
    query = {"_id": waveid}
    key = wave_type
    if wave_type == "vel":
        key = "acc"
    projection = {f"data.{key}.{key}_wave": 1, "data.freq": 1, "_id": 0}
    result = list(collection.find(query, projection))
    aj = {}
    if result:
        wave = get_wave(result[0]["data"][key][f"{key}_wave"])
        freq = result[0]["data"]["freq"]
        aj["freq"] = freq

        isFilter = False

        if waveFilter != "":
            isFilter = waveFilter["status"]

        fmin = 10
        fmax = 1000
        type = "bandpass"
        if wave_type == "vel":

            if isFilter:
                fmin = waveFilter["fmin"]
                fmax = waveFilter["fmax"]
                type = waveFilter["type"]
            
            wave = get_speed(wave, freq, fmin, fmax, type)
            aj['freq'] = freq / 2
            freq = freq / 2
        else:
            if isFilter:
                wave = GetFilter(wave, freq, fmin, fmax, type)

        for item in flag:
            if item == "env":
                aj[item] = GetEnvelope(wave, freq, low, high)
            if item == "wave":
                aj[item] = bef_get_wave(wave, freq)
            if item == "rep":
                aj[item] = get_rep(wave)
            if item == "spec":  # 频谱
                fun = "rectangular"
                specType = "Ewpk"
                if isFilter:
                    fun = assign_value(waveFilter, "fun", "rectangular")
                    specType = assign_value(waveFilter, "specType", "Ewpk")
                aj[item] = GetFFT(wave, freq, fun, specType)
            if item == "erenges":
                aj[item] = get_erenges(wave, freq)
            if item == "hist":
                aj[item] = get_histogram(wave, freq)

        # data = np.array([3.9284, 3.0784, -10.8516, 0.0584, -5.1516, -11.9416, 2.7784, 6.2584] * 1250*6)
        return utils.ok(aj)
        return utils.ok(data.tolist())

        packed_data = msgpack.packb(data.tolist())

        # 使用 Gzip 进行压缩
        compressed_data = gzip.compress(packed_data)

        # 返回压缩后的数据
        return Response(
            compressed_data,
            content_type="application/x-msgpack",
            headers={"Content-Encoding": "gzip"},
        )

    return utils.ok(result)


def get_wave(wave):
    if type(wave) is list:
        return wave

    # 将解压缩后的字节数据转换回浮点数组
    restored_data = np.frombuffer(zlib.decompress(wave), dtype=np.float32).tolist()
    return [round(num, 4) for num in restored_data]


@bluePrint.route("/spec", methods=["post"])
def get_spec():
    try:
        a = request.json
        data = assign_value(a, "data")
        freq = assign_value(a, "freq")
        data = GetFFT(data, freq)
        return utils.ok(data)
    except Exception as e:
        return utils.fail(data=[])


@bluePrint.route("/cep", methods=["post"])
def cep1():
    try:
        a = request.json
        data1 = assign_value(a, "data1")
        data2 = assign_value(a, "data2")
        freq = assign_value(a, "freq")
        amplitude_spectrum, phase_spectrum = get_csd(data1, data2, freq)
        return {
            "code": 0,
            "amplitude_spectrum": amplitude_spectrum,
            "phase_spectrum": phase_spectrum,
        }
    except Exception as e:
        return utils.fail(data=[])


def dilute_list(lst):
    if len(lst) > 10000:
        ratio = (len(lst) - 1) / 9999
        new_lst = [lst[int(i * ratio)] for i in range(9999)]
        new_lst.append(lst[-1])
        return new_lst
    else:
        return lst


@bluePrint.route("/eiges", methods=["post"])
def get_eiges():
    a = request.json
    proj_no = request.json["proj_no"]
    stime = request.json["stime"]
    etime = request.json["etime"]
    saddr = request.json["saddr"]
    sport = request.json["sport"]
    channel = request.json["channel"]
    eigkey = assign_value(a, "eigkey", [])
    mgdb = current_app.mgdb[f"ieplat_{proj_no}"]

    basedbname = f"eige_{sport}_{saddr}"
    dbname = get_collection_name(mgdb, basedbname)
    collection = mgdb[dbname]

    # 构造查询条件和投影参数
    query = {
        "$and": [
            {"_id": {"$gte": f"{sport}_{saddr}_{channel}_{stime}"}},
            {"_id": {"$lte": f"{sport}_{saddr}_{channel}_{etime}"}},
        ]
    }
    projection = {"_id": 1, **{f"data.{e}": 1 for e in eigkey}}
    result = collection.find(query, projection)
    print("eige dbname", dbname)
    result_list = list(result)
    d = dilute_list([{"id": t["_id"][-10:], **t["data"]} for t in result_list])
    return utils.ok(d)


@bluePrint.route("/other", methods=["POST"])
def other():
    a = request.json
    id = assign_value(a, "id")
    device_id = assign_value(a, "device_id")
    sql = f"""
    SELECT s.id,s.address,s.port,s.sensor_name,st.single,s.direction
    from sensor s
    LEFT JOIN sensor_type st on st.id = s.sensor_type
    where s.device_id ={device_id}  and s.id != {id}
    """
    res = db_list(sql)
    list = res["data"]
    arr = []
    arr_ = []
    for item in list:
        single = item["single"]
        if single == 2:
            arr_ = [["V", "Z"], ["A", "X"], ["H", "Y"]]
        else:
            arr_ = [["V", "Z"]]
        for i in arr_:
            arr.append(
                {
                    "id": item["id"],
                    "sensor_name": item["sensor_name"] + i[0],
                    "address": item["address"],
                    "port": item["port"],
                    "axial": i[1],
                }
            )
    res["data"] = arr
    return res


def set_address(address):
    if "_" not in address:
        address += "_0"
    return address


def convert_tuple(lst):
    if len(lst) == 1:
        return f"({lst[0]})"
    else:
        return tuple(lst)


@bluePrint.route("/last/data", methods=["POST"])
def lastData():
    a = request.json
    device_ids = assign_value(a, "device_ids", [])
    flag = assign_value(a, "flag")
    sql = f"""
      SELECT s.sensor_name, s.direction, IFNULL(MAX(w.warn_level), 0) as warn_level, d.device_name,
       s.address, s.port, st.single, r.proj_no, zt.name as zone_name, f.name as factory_name
      FROM sensor s
      LEFT JOIN (SELECT * FROM warn WHERE is_show = 1 AND notice NOT IN (3, 4)) w ON w.sensor_id = s.id
      LEFT JOIN device d ON d.id = s.device_id
      LEFT JOIN sensor_type st ON st.id = s.sensor_type
      LEFT JOIN regionlevel r ON r.id = d.group_id
      LEFT JOIN regionlevel zt ON zt.id = d.zone_id
      LEFT JOIN regionlevel f ON f.id = d.factory_id
      WHERE d.id IN {convert_tuple(device_ids)}
      GROUP BY s.id;
    """
    status_map = ["正常", "一般告警", "中等告警", "严重告警"]
    items = db_list(sql)["data"]
    if not items:
        return {"message": "No sensor data found."}
    zone_name = items[0]["zone_name"]
    factory_name = items[0]["factory_name"]

    def process_sensor_data(item):
        device_name = item["device_name"]
        sensor_name = item["sensor_name"]
        warn_level = item["warn_level"]
        direction = item["direction"]
        proj_no = item["proj_no"]
        port = item["port"]
        address = item["address"] if "_" in item["address"] else item["address"] + "_0"
        mgdb = current_app.mgdb[f"ieplat_{proj_no}"]
        query = {"_id": {"$regex": f"^{port}_{address}"}}
        projection = {}

        dbname = get_collection_name(mgdb, f"eige_{port}_{item['address'].split('_')[0] }")
        collection = mgdb[dbname]
        a = collection.find(query, projection).sort([("_id", -1)]).limit(1)

        extracted_data = [{"id": t["_id"][-10:], **t["data"]} for t in list(a)]
        if extracted_data:
            return {
                "device_name": device_name,
                "sensor_name": sensor_name,
                "status": status_map[warn_level],
                "direction": direction,
                "warn_level": warn_level,
                **extracted_data[0],
            }
        else:
            return {
                "device_name": device_name,
                "sensor_name": sensor_name,
                "status": status_map[warn_level],
                "direction": direction,
                "warn_level": warn_level,
            }

    result = [process_sensor_data(item) for item in items]


    return send_file(
        filename, as_attachment=True, attachment_filename="测点实时数据报表.xlsx"
    )


def get_channel(address):
    parts = address.split("_")
    first_number = str(parts[0])
    second_number = str(parts[1]) if len(parts) > 1 else "0"
    return [first_number, second_number]


def transform_data(input_data):
    if len(input_data) <= 0:
        return []
    data_dict = {}
    for item in input_data:
        device_name = item["device_name"]
        status = item["status"]
        timestamp_seconds = item["id"]
        timestamp_seconds_int = int(timestamp_seconds)
        dt_object = dt_object = datetime.datetime.fromtimestamp(timestamp_seconds_int)
        formatted_time = date_to_str(dt_object)
        sensor_info = {
            "sensor_name": item["sensor_name"],
            "direction": item["direction"],
            "id": formatted_time,
            "Z": item["Z"] if "Z" in item else None,
            "tem": item["tem"] if "tem" in item else "",
        }
        if device_name in data_dict:
            data_dict[device_name]["sensors"].append(sensor_info)
        else:
            data_dict[device_name] = {
                "device_name": device_name,
                "status": status,
                "sensors": [sensor_info],
            }

    result = list(data_dict.values())

    return result
